
`timescale 1ns /1ns

/**
 * 通过串口接收AT指令
 * 
 */
module uart_block(
				input sysclk_i,    			        // 时钟输入
                input reset_i,     				        // 复位输入
                input uart_rx_i,   				        // UART 输入
                
                input [WRITE_BUFFER * 8 - 1:0]     	uart_print_data,        // 待打印的文本
                input [31:0]	                    uart_print_data_len,    // 待打印文本有效长度
                input uart_print_en,                                        // 打印启用有效位
                output uart_print_finish,                                   // 打印完成有效位
                output uart_tx_o); 				                            // UART 输出
                
    parameter READ_BUFFER 	= 128;				// 串口读取缓冲区
    parameter WRITE_BUFFER 	= 128;				// 串口发送缓冲区
    
    
    parameter IDLE 			= 	2'b00;			// 等待状态
    parameter SENDING 		= 	2'b01;			// 发送状态
    parameter FINISHED 		= 	2'b10;			// 完成状态
    
    parameter FLAG_CR 		= 	8'h0D;			// \r符号
    parameter FLAG_LF		= 	8'h0A;			// \n符号
    reg		[1:0]	state 	= 	IDLE;			// 状态寄存器
    reg		[1:0]	next_state = IDLE;			// 下一个状态寄存器
    
    reg     [11:0] 	rstn_cnt = 0;
    wire    		uart_wreq, uart_rvalid;
    wire    [7:0]	uart_wdata;							// 准备写出的数据
    reg		[WRITE_BUFFER * 8 - 1:0]uart_wdata_buffer;	// 写出缓冲区
    integer			uart_wdata_len = 0;					// 准备要写出数据的长度
    reg 	[7:0]	uart_wdata_r;						// 写出数据的寄存器
    
    
    integer 		uart_rdata_len = 0;					// 读取到数据的长度
    wire 	[7:0]	uart_rdata;        					// 当前读取到的数据
    reg		[READ_BUFFER * 8 - 1:0]uart_rdata_r;		// 读取到的数据的缓冲区（用于判断数据是否有改动）
    
    reg     		send_enable = 1'b0;                 // 写出启用
    wire    		send_ready;                     	// 写出准备
    
    
    wire    		read_error;                     	// 写出启用
    wire    		read_valid;                     	// 写出准备
    
    
    
    integer 		uart_wdata_p = 0;					// 数据发送指针
    
    assign uart_rstn_i = rstn_cnt[11];
    assign uart_wdata = uart_wdata_r;					// 写出从reg到wire的转换
    
    // 串口模块
    uart_ip
    (
        // input
        .clk(sysclk_i),             // 共享时钟
        .rst_n(reset_i),            // 复位
        .rxd(uart_rx_i),            // UART输入
        .tx_data(uart_wdata),       // UART 编码前数
        .tx_en(send_enable),        // 输出启用
        
        // output
        .rx_data(uart_rdata),       // UART 解码后数
        .rx_err(read_error),        // 读取错误位
        .rx_vld(read_valid),        // 读取有效位，当收到数据的瞬间会变1，然后变0，上升沿的时候标识数据接收完毕，持续一个时钟的时间。
        .tx_rdy(send_ready),        // 发送准备位
        .txd(uart_tx_o)             // UART输出
    );
    
    assign up_led = {send_enable, send_ready};
    
    
    
    // 下一个状态切换
    always @(*) begin
    	case(state)
        	IDLE: 		next_state = uart_wdata_len > 0 ? SENDING : IDLE;
            	
            SENDING: 	next_state = (uart_wdata_p == uart_wdata_len + 1) ? FINISHED : SENDING;
            	
            FINISHED: 	next_state = (uart_wdata_p == 0 && uart_wdata_len == 0) ? IDLE : FINISHED;
            
            default:	next_state = IDLE;
        endcase
    end
    
    // 状态转移逻辑
	always @(posedge sysclk_i) begin
    	if(!reset_i) begin
    		state <= IDLE;
        end 
        else begin
	        state <= next_state;
        end	
	end
    
    
    // 时序模型控制输出
    always @(posedge sysclk_i) begin
    	if(!reset_i) begin
    		uart_wdata_len <= 0;
            uart_rdata_r <= 0;
        end
        else begin
    		if(state == IDLE) begin
            	if(uart_print_en) begin
                	uart_wdata_buffer <= {uart_print_data, FLAG_CR, FLAG_LF};
                    uart_wdata_len <= uart_print_data_len + 2;
                end
        		else if(read_valid) begin
        
                    // 将接受到的数值移植到接收缓冲区
                    uart_rdata_r = {uart_rdata_r[READ_BUFFER * 8 - 9:0], uart_rdata};
                    uart_rdata_len = uart_rdata_len + 1;			// 读取长度 + 1
                    
                    
                    // 当收到 \r\n 时
                    // 0D = \r     0A = \n
                    if(uart_rdata_r[15:8] == FLAG_CR && uart_rdata_r[7:0] == FLAG_LF) begin
                        // 根据当前接收缓冲区内的内容，修改状态
                        if(uart_rdata_len > 127 
                            || uart_rdata_len < 3 
                            || uart_rdata_r[uart_rdata_len*8 - 1 -: 8] != "A"
                            || uart_rdata_r[(uart_rdata_len - 1) * 8 - 1 -: 8] != "T" ) begin
                            
                            // 
                            uart_wdata_buffer <= {"AT ERROR", FLAG_CR, FLAG_LF};
                            uart_wdata_len <= 10;
                            
                            
                        end
                        else begin
                        
                            // 只是收到AT\r\n
                            if(uart_rdata_len == 4) begin
                                uart_wdata_buffer <= {"AT OK", FLAG_CR, FLAG_LF};
                                //uart_wdata_buffer <= {8'h01};
                                uart_wdata_len <= 7;
                            end 
                            else begin
                                case(uart_rdata_r[39 : 16])
                                    // TODO 开始组播
                                    "+ST" : begin 
                                        uart_wdata_buffer <= {"AT+ST OK", FLAG_CR, FLAG_LF};
                                        uart_wdata_len <= 10;
                                    end 
                                    
                                    // TODO 关闭组播
                                    "+ED" : begin
                                        uart_wdata_buffer <= {"AT+ED OK", FLAG_CR, FLAG_LF}; 
                                        uart_wdata_len <= 10;
                                    end
                                    
                                    default : begin
                                
                                        uart_wdata_buffer <= {"AT ERROR", FLAG_CR, FLAG_LF}; 
                                        uart_wdata_len <= 10;
                                    end
                                    
                                endcase
                            end
                        end 
                        uart_rdata_len <= 0;       	
                    end
                
                end
        	end
    		else if(state == FINISHED) begin
        		uart_wdata_len <= 0;
        	end
        end
        
    end
    
    
    
    // 串口时钟执行发送
    always @(posedge sysclk_i) begin
    
    	if(!reset_i) begin
    		send_enable <= 1'b0;
            uart_wdata_p <= 1'b0;
        end
        else begin
        	if(state == IDLE) begin
            	uart_wdata_p <= 0;
                send_enable <= 1'b0;
            end
        	else if(state == SENDING) begin
        		
                send_enable <= 1'b1;
            	if(send_ready) begin
            
            		// 从最高位开始 每个 8bit 进行发送。
            		uart_wdata_r <= uart_wdata_buffer[(uart_wdata_len - uart_wdata_p) * 8 - 1 -: 8];
            		uart_wdata_p <= uart_wdata_p + 1;
                	
                end
        	end
        	else if(state == FINISHED) begin
        		uart_wdata_p <= 0;
        		send_enable <= 1'b0;
        	end
        end
    	
    end 
    
endmodule
